package at.ac.lbg.media.vis.client.theme.manager
{
	import flare.util.Colors;
	
	import flash.display.Graphics;
	import flash.display.Shape;
	import flash.geom.Point;
	
	import mx.collections.ArrayCollection;
	
	public class PetalLibrary
	{
		public var petals:ArrayCollection = new ArrayCollection();
		private var colorActive:uint;
		private var colorActiveMedium:uint;
		private var colorActiveBright:uint;
		
		private var colorInactive:uint;
		private var colorInactiveBright:uint;
		private var colorInactiveMedium:uint;
		
		private var colorGolden:uint;
		private var colorGoldenMedium:uint;
		private var colorGoldenBright:uint;
		
		private var colorGoldenActive:uint;
		private var colorGoldenActiveMedium:uint;
		private var colorGoldenActiveBright:uint;
		
		private var white:uint = Colors.rgba(254, 254, 254);
		private var lineWidth:Number = 1;
		private var r:int;
		private var rNormal:int = 20;
		private var rNica:int = 20;
		private var innerRadius:int;
		private var p:int;
		private var center:Point;
		private var start:Point;
		private var end:Point;
		private var tip:Point;
		private var active:Boolean;
		private var gradient:Number;
		private var isNica:Boolean;
		
		public function PetalLibrary(colorActive:uint, 
										colorActiveMedium:uint,
										colorActiveBright:uint, 
										colorInactive:uint, 
										colorInactiveBright:uint, 
										colorInactiveMedium:uint,
										colorGolden:uint = 0,
										colorGoldenMedium:uint = 0,
										colorGoldenBright:uint = 0,
										colorGoldenActive:uint = 0,
										colorGoldenActiveMedium:uint = 0,
										colorGoldenActiveBright:uint = 0)
		{
			this.colorActive = colorActive;
			this.colorInactive = colorInactive;
			this.colorInactiveBright = colorInactiveBright;
			
			this.colorActiveBright = colorActiveBright;
			this.colorActiveMedium = colorActiveMedium;
			this.colorInactiveMedium = colorInactiveMedium;
			
			this.colorGolden = colorGolden;
			this.colorGoldenBright = colorGoldenBright;
			this.colorGoldenMedium = colorGoldenMedium;
			
			this.colorGoldenActive = colorGoldenActive;
			this.colorGoldenActiveMedium = colorGoldenActiveMedium;
			this.colorGoldenActiveBright = colorGoldenActiveBright;
			
			petals.addItem(this.defaultR);
			petals.addItem(this.triangle);
			petals.addItem(this.ding);
			petals.addItem(this.leaf);
			petals.addItem(this.needle);
			petals.addItem(this.rect);
			petals.addItem(this.arcLeaf);
			petals.addItem(this.ball);
			petals.addItem(this.arc);
			petals.addItem(this.bigArcLeaf);
			petals.addItem(this.hair);
			petals.addItem(this.litteBall);
			petals.addItem(this.twoLitteBalls);
			petals.addItem(this.spiral);
			petals.addItem(this.litteRect);
			petals.addItem(this.leafStalk);
			petals.addItem(this.antenna);
			petals.addItem(this.narrowRect);
			petals.addItem(this.fork);
			petals.addItem(this.shapeB);
			petals.addItem(this.triangle2);	
			petals.addItem(this.fingers);
			petals.addItem(this.cactus);
			petals.addItem(this.waterdrop);		
		}
		
		
		public function initFlower(centerP:Point, active:Boolean, year:int = 2009, nica:Boolean = false):void {
			if (nica) {
				r = rNica;
				isNica = true;
			} else {
				r = rNormal;
				isNica = false;
			}
			innerRadius = r/2;
			p = r/20;
			this.center = centerP;
			start = getStartPoint(center);
			end = getEndPoint(center);
			tip = new Point(center.x, center.y + r);
			this.active = active;
			this.gradient = getYearGradient(year);

		}
		
		public function initFlowerStack(year:int = 2009, nica:Boolean = false):void {
			if (nica) {
				isNica = true;
			} else {
				isNica = false;
			}
			this.gradient = getYearGradient(year);

		}
		
		public function initPetal(petal:Shape, active:Boolean):void {
			configureGraphicsInner(petal, active);
			
			petal.graphics.moveTo(center.x, center.y);
			petal.graphics.lineTo(start.x, start.y);
			configureGraphicsOuter(petal, active);
			
			
		}
		
		public function initStackedPetal(petal:Shape, active:Boolean):void {
			var g:Graphics = petal.graphics;
			configureGraphicsStack(petal, active);
			g.moveTo(start.x, start.y);
		}
		
		public function initPetalLegend(petal:Shape, active:Boolean):void {
			configureGraphicsLegend(petal, active);
			petal.graphics.lineStyle(lineWidth, colorInactive, 1);
			petal.graphics.moveTo(center.x, center.y);
			petal.graphics.lineTo(start.x, start.y);
		}
		
		public function finishPetal(petal:Shape):void {
			petal.graphics.lineStyle(lineWidth, colorInactive, 0);
		}
		
		public function initHex(centerP:Point):void{
			innerRadius = r/2;
			p = r/20;
			this.center = centerP;
			start = getStartPoint(center);
			end = getEndPoint(center);
			tip = new Point(center.x, center.y + r);
	    }

		
		
		/**********************************************
		 * RENDER FUNCTIONS
		 * *******************************************/
		
		public function defaultR(g:Graphics):void {

			g.lineTo(end.x, end.y);
		}
		
		public function triangle(g:Graphics):void {
			g.lineTo(tip.x, tip.y);
			g.lineTo(end.x, end.y);
		}
		
		public function ding(g:Graphics):void {
			var rightArc:Point = new Point(tip.x + 9*p, tip.y);
			var leftArc:Point = new Point(tip.x - 9*p, tip.y);
			
			g.curveTo(rightArc.x, rightArc.y, tip.x, tip.y);
			g.curveTo(leftArc.x, leftArc.y, end.x, end.y);
		}
		
		public function leaf(g:Graphics):void {
			var rightArc:Point = new Point(tip.x + 6*p, tip.y - 6*p);
			var leftArc:Point = new Point(tip.x - 6*p, tip.y - 6*p);
			
			g.curveTo(rightArc.x, rightArc.y, tip.x, tip.y);
			g.curveTo(leftArc.x, leftArc.y, end.x, end.y);
		}
		
		public function needle(g:Graphics):void {
			var arc:Point = new Point(center.x, center.y + innerRadius);

			g.curveTo(arc.x, arc.y, tip.x, tip.y + 3*p);
			g.curveTo(arc.x, arc.y, end.x, end.y);
		}
		
		public function rect(g:Graphics):void {
			g.lineTo(start.x, tip.y);
			g.lineTo(end.x, tip.y);
			g.lineTo(end.x, end.y);
		}
		
		public function narrowRect(g:Graphics):void {
			g.lineTo(center.x+2, start.y);		
			g.lineTo(center.x+2, tip.y+3);
			g.lineTo(center.x-2, tip.y+3);
			g.lineTo(center.x-2, start.y);
			g.lineTo(end.x, end.y);
		}
		
		public function arcLeaf(g:Graphics):void {
			var rightArc:Point = new Point(tip.x + 10*p, tip.y - 6*p);
			var leftArc:Point = new Point(tip.x + 3*p, tip.y - 6*p);
			
			g.curveTo(rightArc.x, rightArc.y, tip.x, tip.y);
			g.curveTo(leftArc.x, leftArc.y, end.x, end.y);
		}
		
		public function fork(g:Graphics):void {
			var right:Point = new Point(tip.x + innerRadius, tip.y);
			var left:Point = new Point(tip.x - innerRadius, tip.y);
			var middle:Point = new Point(tip.x, tip.y - 5*p);
			
			g.lineTo(right.x, right.y);
			g.lineTo(middle.x, middle.y);
			g.lineTo(left.x, left.y);
			g.lineTo(end.x, end.y);
		}
		
		public function triangle2(g:Graphics):void {
			var right:Point = new Point(tip.x + innerRadius, tip.y);
			var left:Point = new Point(tip.x - innerRadius, tip.y);
			
			g.lineTo(right.x, right.y);
			g.lineTo(left.x, left.y);
			g.lineTo(end.x, end.y);
		}
		
		public function arc(g:Graphics):void {			
			g.curveTo(tip.x, tip.y, end.x, end.y);
		}
		
		public function shapeB(g:Graphics):void {
			var rightArc:Point = new Point(tip.x + 6*p, tip.y);
			var leftArc:Point = new Point(tip.x - 6*p, tip.y);
			var middle:Point = new Point(tip.x, tip.y - innerRadius);
			
			g.curveTo(rightArc.x, rightArc.y, middle.x, middle.y);
			g.curveTo(leftArc.x, leftArc.y, end.x, end.y);
		}
		
		public function bigArcLeaf(g:Graphics):void {
			var rightArc:Point = new Point(tip.x + 6*p, tip.y - 6*p);
			var leftArc:Point = new Point(tip.x - 6*p, tip.y - 6*p);
			
			g.curveTo(rightArc.x, rightArc.y, tip.x, tip.y + 7*p);
			g.curveTo(leftArc.x, leftArc.y, end.x, end.y);
		}
		
		public function hair(g:Graphics):void {		
			g.lineTo(end.x, end.y);
			
			g.moveTo(start.x- innerRadius/2 +3*p, start.y);
			g.lineTo(start.x- innerRadius/2 +3*p, start.y + 6*p);
			
			g.moveTo(start.x- innerRadius/2, start.y);
			g.lineTo(start.x- innerRadius/2, start.y + 9*p);
			
			g.moveTo(start.x- innerRadius/2 -3*p, start.y);
			g.lineTo(start.x- innerRadius/2 -3*p, start.y + 6*p);
		}
		
		public function litteBall(g:Graphics):void {		
			g.lineTo(end.x, end.y);
			
			g.moveTo(start.x - innerRadius/2, start.y);
			g.lineTo(start.x - innerRadius/2, start.y + 6*p);
			g.drawCircle(start.x - innerRadius/2, start.y + 9*p, 3*p);
		}
		
		public function ball(g:Graphics):void {		
			g.lineTo(end.x, end.y);
			g.drawCircle(center.x, start.y + 5*p, 5*p);
		}
		
		public function twoLitteBalls(g:Graphics):void {		
			g.lineTo(end.x, end.y);
			
			g.drawCircle(tip.x, tip.y, 3*p);
			g.drawCircle(tip.x, tip.y - 7*p, 4*p);
		}
		
		public function litteRect(g:Graphics):void {		
			g.lineTo(end.x, end.y);
			
			g.moveTo(tip.x, start.y);
			g.lineTo(tip.x, start.y + 6*p);
			g.drawRect(tip.x - 4*p, tip.y - 5*p, 8*p, 5*p);
		}
		
		public function leafStalk(g:Graphics):void {		
			var rightArc:Point = new Point(tip.x + 6*p, tip.y - 6*p);
			var leftArc:Point = new Point(tip.x - 6*p, tip.y - 6*p);
			
			g.curveTo(rightArc.x, rightArc.y, tip.x, tip.y);
			g.curveTo(leftArc.x, leftArc.y, end.x, end.y);
			g.moveTo(center.x, start.y+2*p);
			g.lineTo(tip.x, tip.y);
		}
		
		public function antenna(g:Graphics):void {
			g.lineTo(tip.x, tip.y-3*p);
			g.lineTo(end.x, end.y);
			g.moveTo(tip.x, tip.y-3*p);
			g.lineTo(tip.x + 3*p, tip.y + 3*p);
			g.moveTo(tip.x, tip.y-3);
			g.lineTo(tip.x - 3*p, tip.y + 3*p);
		}
		
		// centerX-- X origin of the spiral.
		// centerY-- Y origin of the spiral.
		// radius--- Distance from origin to outer arm.
		// sides---- Number of points or sides along the spiral's arm.
		// coils---- Number of coils or full rotations. (Positive numbers spin clockwise, negative numbers spin counter-clockwise)
		// rotation- Overall rotation of the spiral. ('0'=no rotation, '1'=360 degrees, '180/360'=180 degrees)
		//
		public function spiral(g:Graphics):void {
			var radius:Number = 5*p;
			var sides:Number = 40*p;
			var coils:Number = 2*p;
			var rotation:Number = 0.75;
			var spiralCenter:Point = new Point(center.x, start.y+radius+3);
			
			g.lineTo(end.x, end.y);
			g.endFill();
			
			g.moveTo(center.x, start.y);
			g.lineTo(center.x, start.y+3*p);
			
	        g.moveTo(spiralCenter.x, spiralCenter.y);
	        
	        //
	        // How far to step away from center for each side.
	        var awayStep:Number = radius/sides;
	        //
	        // How far to rotate around center for each side.
	        var aroundStep:Number = coils/sides;// 0 to 1 based.
	        //
	        // Convert aroundStep to radians.
	        var aroundRadians:Number = aroundStep * 2 * Math.PI;
	        //
	        // Convert rotation to radians.
	        rotation *= 2 * Math.PI;
	        //
	        // For every side, step around and away from center.
	        for (var i:int =1; i<=sides; i++){
	            //
	            // How far away from center
	            var away:Number = i * awayStep;
	            //
	            // How far around the center.
	            var around:Number = i * aroundRadians + rotation;
	            //
	            // Convert 'around' and 'away' to X and Y.
	            var x:Number = spiralCenter.x + Math.cos(around) * away;
	            var y:Number = spiralCenter.y + Math.sin(around) * away;
	            //
	            // Now that you know it, do it.
	            g.lineTo(x, y);
	        }
		    
		}
		
		public function fingers(g:Graphics):void {		
			g.lineTo(end.x, end.y);
			
			g.moveTo(start.x- innerRadius/2, start.y);
			g.lineTo(start.x- innerRadius/2 +3*p, start.y + 6*p);
			g.moveTo(start.x- innerRadius/2, start.y);
			g.lineTo(start.x- innerRadius/2, start.y + 9*p);
			g.moveTo(start.x- innerRadius/2, start.y);
			g.lineTo(start.x- innerRadius/2 -3*p, start.y + 6*p);
		}
		
		
		public function cactus(g:Graphics):void {			
			g.curveTo(tip.x, tip.y + 5*p, end.x, end.y);
			g.moveTo(tip.x, tip.y - 3*p);
			g.lineTo(tip.x, tip.y + 2*p);
			// left
			g.moveTo(tip.x-3*p, tip.y - 6*p);
			g.lineTo(tip.x-6*p, tip.y - 1*p);
			
			g.moveTo(tip.x, tip.y - 3*p);
			g.lineTo(tip.x, tip.y + 2*p);
			// right
			g.moveTo(tip.x+3*p, tip.y - 6*p);
			g.lineTo(tip.x + 6*p, tip.y - 1*p);
			
			g.moveTo(tip.x, tip.y - 3);
			g.lineTo(tip.x, tip.y + 2*p);
		}
		
		public function waterdrop(g:Graphics):void {
			var arc1:Point = new Point(center.x + 3*p, start.y + 3*p);
			var arc2:Point = new Point(center.x - 3*p, start.y + 3*p);

			g.curveTo(arc2.x, arc2.y, tip.x + 4*p, tip.y-2*p);
			g.curveTo(tip.x, tip.y + 5*p, tip.x - 4*p, tip.y - 2*p);
			
			g.curveTo(arc1.x, arc1.y, end.x, end.y);
		}
		
		/**********************************************
		 * /END RENDER FUNCTIONS
		 * *******************************************/
		 
		 
		public function getStartPoint(center:Point):Point {
			var start:Point = new Point(center.x, center.y);
			start.x += innerRadius/2;
			start.y += Math.sqrt(Math.pow(innerRadius, 2) - Math.pow(innerRadius/2, 2)); 
			return start;
		}
		
		private function getEndPoint(center:Point):Point {
			var end:Point = new Point(center.x, center.y);
			end.x -= innerRadius/2;
			end.y += Math.sqrt(Math.pow(innerRadius, 2) - Math.pow(innerRadius/2, 2)); 
			return end;
		}
		
		private function configureGraphicsInner(petal:Shape, activePetal:Boolean):void {
			var g:Graphics = petal.graphics;
			if (isNica) {
				if (active && !activePetal){
					g.lineStyle(lineWidth, getYearColor(colorGoldenActiveMedium), 1);
					g.beginFill(getYearColor(colorGoldenActiveBright), 1);

				} else if (activePetal) {
					g.lineStyle(lineWidth, getYearColor(colorGoldenActiveMedium), 1);
					g.beginFill(getYearColor(colorGoldenActiveMedium), 1);
					
				} else {
					g.lineStyle(lineWidth, getYearColor(colorGoldenMedium), 1);
					g.beginFill(getYearColor(colorGoldenBright), 1);
				}
			} else {
				if (active && !activePetal){
					g.lineStyle(lineWidth, getYearColor(colorActiveMedium), 1);
					g.beginFill(getYearColor(colorActiveBright), 1);
	
				} else if (activePetal) {
					g.lineStyle(lineWidth, getYearColor(colorActiveMedium), 1);
					g.beginFill(getYearColor(colorActiveMedium), 1);
					
				} else {
					g.lineStyle(lineWidth, getYearColor(colorInactiveMedium), 1);
					g.beginFill(getYearColor(colorInactiveBright), 1);
				}
			}
		}
		
		private function configureGraphicsOuter(petal:Shape, activePetal:Boolean):void {
			var g:Graphics = petal.graphics;
			if (isNica) {
				if (active) {
					g.lineStyle(lineWidth, getYearColor(colorGoldenActive), 1);
				} else {
					g.lineStyle(lineWidth, getYearColor(colorGolden), 1);
				}
			} else {
				if (active) {
					g.lineStyle(lineWidth, getYearColor(colorActive), 1);
					
				} else {
					g.lineStyle(lineWidth, getYearColor(colorInactive), 1);
					
				}
			}
		}
		
		private function configureGraphicsStack(petal:Shape, activePetal:Boolean):void {
			var g:Graphics = petal.graphics;
			if (active) {
				g.lineStyle(1, getYearColor(colorActive), 1);
			} else {
				g.lineStyle(1, getYearColor(colorInactive), 1);
			}
		}
		
		private function configureGraphicsLegend(petal:Shape, activePetal:Boolean):void {
			var g:Graphics = petal.graphics;
			if (active && !activePetal){
				g.lineStyle(lineWidth, colorActive, 1);
				g.beginFill(colorInactiveBright, 1);
			} else if (activePetal) {
				g.lineStyle(lineWidth, colorActive, 1);
				g.beginFill(colorActiveBright, 1);
			} else {
				g.lineStyle(lineWidth, colorInactive, 1);
				g.beginFill(colorInactiveBright, 1);
				
			}
		}
		
		private function getYearGradient(year:int):Number {
			var firstYear:int = 1990;
			var lastYear:int = 2009;
			var allyears:int = lastYear - firstYear;
			var yeardiff:int = year - firstYear;
			var gradient:Number = ((100/allyears) * yeardiff) /100;
			return gradient;
		}
			
		private function getYearColor(color:uint):uint {
			return brighter(color, 1 - gradient);
			
		}
		
			    /**
	     * Get a brighter shade of an input color.
	     * @param c a color value
	     * @return a brighter color value
	     */
	    private static function brighter(c:uint, s:Number=1):uint
	    {
	    	var cr:uint, cg:uint, cb:uint, i:uint;
	    	s = Math.pow(0.7, s);
	    	
	        cr = Colors.r(c), cg = Colors.g(c), cb = Colors.b(c);
	        i = 60;
	        if (cr == 0 && cg == 0 && cb == 0) {
	           return Colors.rgba(i, i, i, 1);
	        }
	        if ( cr > 0 && cr < i ) cr = i;
	        if ( cg > 0 && cg < i ) cg = i;
	        if ( cb > 0 && cb < i ) cb = i;
	
	        return Colors.rgba(Math.min(250, (int)(cr/s)),
	                    Math.min(250, (int)(cg/s)),
	                    Math.min(250, (int)(cb/s)),
	                    1);
	    }
	    
	}
}